package org.hagen.mmia.yars.client;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.lucene.queryparser.classic.ParseException;
import org.hagen.mmia.yars.agent.CollabSupport;
import org.hagen.mmia.yars.agent.Query;
import org.hagen.mmia.yars.agent.QueryPool;
import org.hagen.mmia.yars.agent.utils.FloatTreeMap;
import org.hagen.mmia.yars.collection.Collection;
import org.hagen.mmia.yars.collection.Document;
import org.hagen.mmia.yars.collection.Topic;
import org.hagen.mmia.yars.engine.Index;
import org.xml.sax.SAXException;

import net.*;

/*
 * 
 */
class SyncExperiment {

	private  CollabSupport docsOpt = new CollabSupport();
	
	/*
	 * 
	 */
	public void run( int topicId, Map<String,FloatTreeMap> queryPool, int[] usrIdx, int mode, SyncMeasures meas ) {

		ArrayList<User> users = new ArrayList<User>();
		
		Topic topic = Collection.topics.get(topicId);

		/////////////////////////////////////////////////////////////////////////////////
		// setup users
	
		for( int uID = 0; uID < User.MAX_NO_OF_USERS; uID ++ ) {

			User user = new User( uID, docsOpt, new Query(Index.getReader() ) );

			user.setRel( topic.relSet );
			
			int randomPoolID = usrIdx[ uID ];
			FloatTreeMap skills = ( FloatTreeMap ) queryPool.values().toArray()[ randomPoolID ];
			String		 query  = ( String )queryPool.keySet().toArray()[randomPoolID ];
					
			user.addSkills( skills );
			user.setInitialQuery( query ); 

			users.add( user );
		}
		
		/////////////////////////////////////////////////////////////////////////////////
		// run single iteration test

		// USER: execute query and store results
		
		for( User u : users ) {
			if( ! u.access( ) ) {
				System.out.println( "skipping topic " + topic.ID );
				return;
			}
		}		

		// SYSTEM: optimize result cloud
		this.docsOpt.initialize();
		this.docsOpt.buildSharedResultSet( users, mode );
		this.docsOpt.solve(users);
		
		// USER: fetch results and assess
		for( User u : users ) {
			u.orientate( );
		}

		/////////////////////////////////////////////////////////////////////////////////
		// evaluate results
		
		int cov = 0, relCov = 0;
		for( User u : users ) {

			Query q = u.getPastQuery();

			relCov = meas.relevantCoverage( q );
			cov    = meas.coverage( q );			
		}		
		
		double recall 	 = ( double )relCov / ( double )topic.relSet.size();
		double precision = ( double )relCov	/ ( double )( cov );

		DecimalFormat format = new DecimalFormat("##0.0000");

		System.out.print( "RECALL@" + User.MAX_HITS_PER_USER + ": " + format.format( recall ) + " " + format.format( precision ) );
		
		System.out.println( " RelCoverage: " + relCov + " Coverage: " + cov );
	}
}

/*
 * 
 */
public class Hagen {

	// some general simulation parameters:
	static public final int NUMBER_OF_DOCUMENTS = 20;

	/*
	 * 
	 */
	private static final boolean verbose = false;
	
	public Hagen() {
	}
	
	/*
	 * 
	 */
	public static void main(String[] args) throws IOException, ParseException, SAXException, ParserConfigurationException {

		// initialize some data

		if( args.length != 2 ) {
			// default behavior
			Index.loadIndex( Index.CollectionSize.HUGE );
		} else {
			if( args[0] == "-index" ) {

				if( args[1] == "LARGE" ) {
					Index.createIndex( Index.CollectionSize.LARGE );		
					System.err.println( "LARGE index creation done" );
					return;
				} else if( args[1] == "HUGE" ) {
					Index.createIndex( Index.CollectionSize.HUGE );
					System.err.println( "HUGE index creation done" );
					return;
				} else {
					System.err.println( "unknown program parameter. Use -index [HUGE|LARGE] or -run [HUGE|LARGE]" );
				}

			} else if( args[0] == "-run" ) {

				if( args[1] == "LARGE" ) {
					Index.loadIndex( Index.CollectionSize.HUGE );
				} else if( args[1] == "HUGE" ) {
					Index.loadIndex( Index.CollectionSize.LARGE );
				} else {
					System.err.println( "unknown program parameter. Use -index [HUGE|LARGE] or -run [HUGE|LARGE]" );
				}				
				
			} else {
				System.err.println( "unknown program parameter. Use -index [HUGE|LARGE] or -run [HUGE|LARGE]" );
			}
		}
		
		//Global.printIndex();
		//Global.printTopics();

		User.MAX_NO_OF_USERS		= 1;
		User.MAX_EXPERIMENT_RUNS	= 1;		
		User.MAX_DOCS_PER_QUERY	= 350;
		System.out.println( "STARTING FOR user " + User.MAX_NO_OF_USERS + " runs " + User.MAX_EXPERIMENT_RUNS );
		start();

		User.MAX_NO_OF_USERS		= 2;
		User.MAX_EXPERIMENT_RUNS	= 1;		
		User.MAX_DOCS_PER_QUERY	= 700;
		System.out.println( "STARTING FOR user " + User.MAX_NO_OF_USERS + " runs " + User.MAX_EXPERIMENT_RUNS );
		start();

		User.MAX_NO_OF_USERS		= 3;
		User.MAX_EXPERIMENT_RUNS	= 1;		
		User.MAX_DOCS_PER_QUERY	= 1050;
		System.out.println( "STARTING FOR user " + User.MAX_NO_OF_USERS + " runs " + User.MAX_EXPERIMENT_RUNS );
		start();

		User.MAX_NO_OF_USERS		= 4;
		User.MAX_EXPERIMENT_RUNS	= 1;		
		User.MAX_DOCS_PER_QUERY	= 1400;
		System.out.println( "STARTING FOR user " + User.MAX_NO_OF_USERS + " runs " + User.MAX_EXPERIMENT_RUNS );
		start();

		User.MAX_NO_OF_USERS		= 5;
		User.MAX_EXPERIMENT_RUNS	= 1;		
		User.MAX_DOCS_PER_QUERY	= 1750;
		System.out.println( "STARTING FOR user " + User.MAX_NO_OF_USERS + " runs " + User.MAX_EXPERIMENT_RUNS );
		start();

		User.MAX_NO_OF_USERS		= 6;
		User.MAX_EXPERIMENT_RUNS	= 1;		
		User.MAX_DOCS_PER_QUERY	= 2100;
		System.out.println( "STARTING FOR user " + User.MAX_NO_OF_USERS + " runs " + User.MAX_EXPERIMENT_RUNS );
		start();
		
	}	
	
	@SuppressWarnings("deprecation")
	public static void start() throws IOException, ParseException, SAXException, ParserConfigurationException {
		
		for( int i=0; i<Collection.topics.size(); i++ ) {
			Topic topic = Collection.topics.get(i);
			
			if( topic.relSet.size() >= NUMBER_OF_DOCUMENTS ) { 
				
				System.out.println( "TOPIC: " + topic.ID
						  + " RELEVANT DOCS: " + topic.relSet.size()
						  + " QUERY LENGTH: " + topic.getDistinctTermCount() );

				Map<String,FloatTreeMap> queryPool = QueryPool.generateQueries( topic.relSet );

				SyncExperiment exp1 = new SyncExperiment();
				SyncExperiment exp2 = new SyncExperiment();	
				SyncExperiment exp4 = new SyncExperiment();	

				// initialize buffers due to new queries in next experiment run
				Iterator<Entry<String,Document>> it = Collection.documents.entrySet().iterator();
				while( it.hasNext() ) {
					Entry<String,Document> e = it.next();
					e.getValue().initScores();
				}

				// create random numbers for queries (need for all assessment capacities)
				int userIdx[] = new int[User.MAX_NO_OF_USERS];

				for( int uID = 0; uID < User.MAX_NO_OF_USERS; uID ++ ) {
					userIdx[ uID ] = uID;
				}				
				
				// iterate over all assessment capacities
				int assessmentDepths[] = { 20, 50, 80, 120, 160, 200, 240, 320 };
				for( int l=0; l<8; l++ ) {

					User.MAX_HITS_PER_USER = assessmentDepths[l];

					SyncMeasures naive = new SyncMeasures();
					SyncMeasures split = new SyncMeasures();
					SyncMeasures ilp = new SyncMeasures();
					
					exp1.run( i, queryPool, userIdx, CollabSupport.PRP, naive );
					exp2.run( i, queryPool, userIdx, CollabSupport.RR_SPLIT, split );
					exp4.run( i, queryPool, userIdx, CollabSupport.ILP, ilp );

					System.out.println( "-----------------------------------------------" );
				}
			} // END OF TOPIC
		}
	}
}

